package com.fish;
/**
* @author Dror
*
* email: gumjum.o.o@gmail.com
*
*/
import java.awt.Color;
import java.awt.Graphics;
import java.util.ArrayList;
import java.util.Random;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import com.fileio.FileIO;
import com.graphics.Box;
import com.graphics.Camera;
import com.graphics.ConnectingOval;
import com.graphics.Oval;
import com.graphics.Shape;
import com.math.Quat;
import com.math.Vector;
public class Fish extends Shape{
public static Random rand = new Random();
public int FOOD_HEALTH_LIMIT = 9;
boolean inFishTank = true;
boolean selected = false;
int counter = 999;
public Route route;
//information:
public String type = "goldfish";
public String name = "larry";
public String status = "";
public String ginfo = "";
public float size;
public float age = 0.0f;
public float health = 10f;
public float value = -1;
public float fvalue = -1;
public float VICIN = 20;
public float speed = 1f;
public float fspeed = 1f;
public String wantedFoodType;
FishFood fd;
Fish wantedfish;
public int SHAPE_NUM = 10;
ArrayList<Shape> shapeS;
public ConnectingOval shape[];
public Box boarderBox;
Vector target;
private boolean FISH_EATER = false;
private boolean DEAD = false;
public Fish(Camera cam,Vector dim,Vector pos,Quat rot,String type){
shapeS = new ArrayList<>();
this.cam = cam;
d = new Vector(dim);
this.color = Shape.int2color(6);
points_num = Route.FORWARD_STATE_NUM+2+2;
points = new Vector[points_num];
x = new int[points_num];
y = new int[points_num];
this.p = new Vector(pos);
this.r = new Quat(rot);
target = new Vector(0,0,0);
shape = buildMeSomeFish(type,this);
SHAPE_NUM = shape.length;
this.type = type;
build();
fishInRoute();
rebuild();
}
public void build(){
boarderBox = new Box(this.cam,this.d,this.p,this.r,this.color);
boarderBox.setTransparent(true);
boarderBox.only_lines = true;
for(int i = 0;i<SHAPE_NUM-1;i++){
for(int j = 0,k = shape[i].half;j<shape[i].half;j++,k++){
shape[i].bridgPoint(k, shape[i+1].points[j]);
}
}
for(int i =0;i<SHAPE_NUM;i++)
World.shapes.add(shape[i]);
setTarget(p);
route = new Route(this);
route.calcNewRoute();
for(int i=0;i<points_num;i++)
points[i] = new Vector();
}
/**
* move one step in the simulation
*/
public void fishStep(){
/*
* create the square for the mouse
*/
points[0].set( d.x, d.y, d.z);
points[0].transformation(r, p);
points[1].set(-d.x,-d.y,-d.z);
points[1].transformation(r, p);
if(!DEAD){
counter++;
if(counter>1000){
this.age += 1;
this.health -= 0.5;
if(health > 5)
this.updateSize(0.01f);
this.value = fvalue/2*size;
speed = fspeed + (size - age + health)/20;
if(health < 0){
World.shapes.remove(this);
return;
}
counter = 0;
}
checkFishFood();
route.stepForward();
fishInRoute();
}else{
tmp.set(0,0.05f,0);
p.setSub(tmp);
for(Shape s :this.shape)
s.p.setSub(tmp);
if(!World.isInBox(World.fishtank.boxes[0],p)){
World.sim_shapes.remove(this);
for(Shape s: this.shape)
World.shapes.remove(s);
}
}
}
/**
* check about the fish food, if the fish need to eat, if the fish can eat etc...
*/
private void checkFishFood() {
if(FISH_EATER && wantedfish != null && this.health < FOOD_HEALTH_LIMIT){
tmp.set(shape[0].p);
tmp.setSub(wantedfish.p);
if(tmp.length() < wantedfish.d.length()+this.d.length()){
wantedfish.dead();
health += 1;
this.updateSize(wantedfish.size/6f);
wantedfish = null;
age -= (1000-counter)/1000f;
counter = 999;
}
}if(!FISH_EATER && fd != null && this.health < FOOD_HEALTH_LIMIT){
tmp.set(shape[0].p);
tmp.setSub(fd.p);
if(tmp.length() < 1){
World.shapes.remove(fd);
World.sim_shapes.remove(fd);
fd = null;
health += 1;
this.updateSize(0.1f);
counter = 999;
}
}
}
/**
* converts the fish into a dead fish
*/
private void dead() {
this.type = "deadfish";
this.DEAD = true;
for(Shape s:shape)
World.shapes.remove(s);
this.shape = Fish.buildMeSomeFish("deadfish", this);
for(Shape s:shape)
World.shapes.add(s);
fishInRoute();
}
/**
* Updates the fish size by a factor {@code f}.
* @param f
* the size factor
*/
private void updateSize(float f) {
this.size += f;
this.d.setAdd(f*d.x,f*d.y,f*d.z);
for(ConnectingOval o: shape){
o.d.setAdd(f*o.d.x, f*o.d.y, f*o.d.z);
}
this.boarderBox.d.setAdd(f*d.x,f*d.y,f*d.z);
}
public void changeColor(int i){
this.def_color = int2color(i);
for(Oval x: shape)
x.def_color = int2color(i);
}
/**
* place all the {@link ConnectingOval} in place, according to the calculated route.
*/
private void fishInRoute(){
shape[0].p.set(route.backward[0].p);
shape[0].r.set(route.backward[0].r);
for(int i=1;i<SHAPE_NUM;i++){
tmp.set(0,0,-(shape[i].d.z + shape[i-1].d.z));
tmp.transformation(shape[i-1].r, shape[i-1].p);
shape[i].p.set(tmp);
shape[i].r.set(route.backward[i].r);
}
tmp.set(0,0,0);
tmpQ.set(0,0,0,0);
for(int i = 0;i<SHAPE_NUM;i ++){
tmp.setAdd(shape[i].p);
tmpQ.setAdd(shape[i].r);
}
tmp.setScale(1f/SHAPE_NUM);
tmpQ.setScale(1f/SHAPE_NUM);
tmpQ.normalize();
p.set(tmp);
r.set(tmpQ);
}
/**
* Determine the fish target if the fish is in the point {@code sp}.
* @param sp
* the point
*/
public void setTarget(Vector sp){
if(FISH_EATER && health < FOOD_HEALTH_LIMIT)
wantedfish = World.getClosestFish(sp,wantedFoodType);
else if(health < FOOD_HEALTH_LIMIT)
fd = World.getClosestFood(sp);
if(FISH_EATER && wantedfish != null && health < FOOD_HEALTH_LIMIT){
target.set(wantedfish.p);
}else if(!FISH_EATER && fd != null && health < FOOD_HEALTH_LIMIT){
target.set(fd.p);
}
else{
// Fish f = World.getFirstOfType(this.type);
Fish f = World.getClosestFishWithoutFish(sp,this.type,this);
if(f != null){
Vector p = f.p;
while(true){
tmp.set(rand.nextFloat()-0.5f,rand.nextFloat()-0.5f,rand.nextFloat()-0.5f);
float mag = tmp.length();
tmp.setScale(VICIN/mag);
target.x = (p.x + tmp.x);
target.y = (p.y + tmp.y);
target.z = (p.z + tmp.z);
if(World.isInBox(World.fishtank.boxes[0],target))
break;
}
}else{
while(true){
tmp.set(rand.nextFloat(),rand.nextFloat(),rand.nextFloat());
float mag = tmp.length();
tmp.setScale(VICIN/mag);
target.x = (p.x + tmp.x);
target.y = (p.y + tmp.y);
target.z = (p.z + tmp.z);
if(World.isInBox(World.fishtank.boxes[0],target))
break;
}
}
}
}
public void rebuild() {
// if(debug){
boarderBox.p.set(this.p);
boarderBox.r.set(this.r);
boarderBox.d.set(this.d);
// }
for(int i=2;i<points_num-2;i++){
points[i].set(route.forward[i-2].p);
}
points[points_num-2].set(route.forward[0].target);
points[points_num-1].set(this.p);
for(Vector j: points){
j.reverseTransformation(cam.r, cam.p);
}
tmp.reverseTransformation(cam.r, cam.p,p);
compare_z = (int)(tmp.z);
}
public void show(Graphics g) {
convert(points, x, y);
// if(debug){ //debug stuff
//show boarders:
boarderBox.xshow(g);
//draw next steps points:
g.setColor(Color.green);
for(int i=2;i<points_num-3;i++)
if(points[i].z > 0 && points[i+1].z > 0)
g.drawLine(x[i], y[i], x[i+1], y[i+1]);
//draw the mouse rectangle
g.setColor(Color.blue);
if(points[0].z > 0 && points[1].z > 0)
g.drawRect(Math.min(x[0], x[1]),Math.min(y[0], y[1]), Math.abs(x[1]-x[0]), Math.abs(y[1]-y[0]));
//draw the fish -> target line
g.setColor(Color.white);
if(points[points_num-2].z > 0 && points[points_num-1].z > 0)
g.drawLine(x[points_num-2], y[points_num-2], x[points_num-1], y[points_num-1]);
// }
}
public Element toXML(Document doc){
Element fish = doc.createElement("Fish");
fish.setAttribute("position", p+"");
fish.setAttribute("rotation", r+"");
fish.setAttribute("dimmention", d+"");
fish.setAttribute("type", type);
fish.setAttribute("name", name);
fish.setAttribute("status", status);
fish.setAttribute("fishInRoutegeneralInfo", ginfo);
fish.setAttribute("size", size+"");
fish.setAttribute("age", age+"");
fish.setAttribute("health", health+"");
fish.setAttribute("value", value+"");
fish.setAttribute("vicinity", VICIN+"");
fish.setAttribute("speed", fspeed+"");
fish.setAttribute("fishEating", FISH_EATER+"");
fish.setAttribute("wantedFoodType", wantedFoodType+"");
return fish;
}
public static Fish fromXML(Element e, Camera cam){
Vector p = Vector.parseVector(e.getAttribute("position"));
Quat r = Quat.parseQuat(e.getAttribute("rotation"));
Vector d = Vector.parseVector(e.getAttribute("dimmention"));
String type = e.getAttribute("type");
Fish f = new Fish(cam,d,p,r,type);
f.name = e.getAttribute("name");
f.fvalue = Float.parseFloat(e.getAttribute("value"));
f.value = f.fvalue;
f.size = Float.parseFloat(e.getAttribute("size"));
f.VICIN = Float.parseFloat(e.getAttribute("vicinity"));
f.fspeed = Float.parseFloat(e.getAttribute("speed"));
f.speed = f.fspeed + (f.size - f.age + f.health)/20;
f.ginfo = e.getAttribute("generalInfo");
f.FISH_EATER = Boolean.parseBoolean(e.getAttribute("fishEating"));
f.wantedFoodType = e.getAttribute("wantedFoodType");
return f;
}
public static ConnectingOval [] buildMeSomeFish(String type,Fish f){
Element builder = (Element)FileIO.builderDB.getElementsByTagName("builder").item(0);
Element e = (Element)builder.getElementsByTagName(type).item(0);
int num = Integer.parseInt(e.getAttribute("num"));
ConnectingOval [] ovals = new ConnectingOval[num];
for(int i = 0;i<num;i++){
ovals[i] = ConnectingOval.fromXML((Element) e.getElementsByTagName("ConnectingOval").item(i), f.cam);
ovals[i].d.set(ovals[i].d.x*f.d.x,ovals[i].d.y*f.d.y,ovals[i].d.z*f.d.z);
}
return ovals;
}
public void toggle_lines(){
this.only_lines = !this.only_lines;
for(ConnectingOval o: shape){
o.only_lines = this.only_lines;
}
}
}